
import math
from PyQt4.QtGui import QDialog
from S3D import QtHelper
from S3D.Sound import DbToVolume, VolumeToDb
from S3D.Tools.Sound.MindistCalc.UI import MindistCalc

TITLE_ICON = QtHelper.loadIcon("MindistCalc")

MAX_VOLUME      = 0
MIN_DISTANCE    = 1
HEAD_VOLUME     = 2
HEAD_DISTANCE   = 3

_PROPS = [
    "maxVolume",
    "minDist",
    "headVolume",
    "headDist",
]

def _calcMaxVolume(self):
    headVolume          = DbToVolume(self.cfg.headVolume)
    minDist_0           = headVolume * self.cfg.headDist # min distance for 0 dB
    maxVolume           = minDist_0 / self.cfg.minDist if minDist_0 < self.cfg.minDist else 1.0
    print("maxVolume = %s" % (VolumeToDb(maxVolume)))
    return VolumeToDb(maxVolume)

def _calcMinDist(self):
    headVolume          = DbToVolume(self.cfg.headVolume)
    minDist_0           = headVolume * self.cfg.headDist # min distance for 0 dB
    maxVolume           = DbToVolume(self.cfg.maxVolume)
    print("minDist = %s" % (minDist_0 / maxVolume))
    return minDist_0 / maxVolume if maxVolume > 0 else 0.0

def _calcHeadVolume(self):
    maxVolume           = DbToVolume(self.cfg.maxVolume)
    minDist_0           = maxVolume * self.cfg.minDist # min distance for 0 dB
    headVolume          = minDist_0 / self.cfg.headDist if minDist_0 < self.cfg.headDist else 1.0
    print("headVolume = %s" % (VolumeToDb(headVolume)))
    return VolumeToDb(headVolume)

def _calcHeadDist(self):
    maxVolume           = DbToVolume(self.cfg.maxVolume)
    minDist_0           = maxVolume * self.cfg.minDist # min distance for 0 dB
    headVolume          = DbToVolume(self.cfg.headVolume)
    print("headDist = %s" % (minDist_0 / headVolume))
    return minDist_0 / headVolume if headVolume < maxVolume else self.cfg.minDist

_RECALC_PROCS = [
    _calcMaxVolume,
    _calcMinDist,
    _calcHeadVolume,
    _calcHeadDist,
]

class MainWindow(QDialog):
    def __init__(self, cfg):
        super(MainWindow, self).__init__()

        self.ui = MindistCalc.Ui_MindistCalc()
        self.ui.setupUi(self)

        self.setWindowIcon(TITLE_ICON)

        self.cfg = cfg
        self.initUi()

        self.show()

    def initUi(self):
        self.dataBind = QtHelper.DataBind()

        cls = type(self)
        for prop in _PROPS:
            p = property(_makeGetter(prop), _makeSetter(prop))
            setattr(cls, prop, p)

            ctrl = getattr(self.ui, "%sEdit" % prop)
            self.dataBind.bindValue(ctrl, self, prop)

        radioList = [getattr(self.ui, "%sCheck" % prop) for prop in _PROPS]
        self.dataBind.bindRadio(radioList, self, "calcTarget")

        self.dataBind.updateValues()

    @property
    def calcTarget(self):
        return self.cfg.calcTarget

    @calcTarget.setter
    def calcTarget(self, index):
        self.cfg.calcTarget = index

    def recalcPropBy(self, index):
        target = self.cfg.calcTarget
        if index == target:
            if target == MIN_DISTANCE:
                target = HEAD_DISTANCE
            else:
                target = MIN_DISTANCE

        prop = _PROPS[target]
        calc = _RECALC_PROCS[target]
        value = calc(self)

        # round volumes to 0.5
        if target == MAX_VOLUME or target == HEAD_VOLUME:
            value = math.trunc((value * 2.0) + (0.5 if value > 0 else -0.5)) / 2.0

        setattr(self.cfg, prop, value)
        self.dataBind.updateValues()

def _makeGetter(prop):
    def getter(self):
        return getattr(self.cfg, prop)
    return getter

def _makeSetter(prop):
    def setter(self, value):
        setattr(self.cfg, prop, value)
        self.recalcPropBy(_PROPS.index(prop))
    return setter
